﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Logic;
using System.IO;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            ResourceManager.Init();
            //Network n = Network.LoadNetwork(Properties.Settings.Default.NNDescriptionPath);
            BpNetwork n = BpNetwork.LoadNetwork(Properties.Settings.Default.NNDescriptionPath);

            var inputDataSet = new List<float[]>();
            foreach (String s in File.ReadLines(Properties.Settings.Default.InputDataPath))
            {
                String[] tmp = s.Split();
                var input = new float[tmp.Length];
                for (int i = 0; i < tmp.Length; i++)
                    input[i] = float.Parse(tmp[i]);
                inputDataSet.Add(input);
            }

            if ((n.Layers[0] as BpLayer) != null)
            {
                var trainingDataSet = new List<float[]>();
                foreach (String s in File.ReadLines(Properties.Settings.Default.TrainingDataPath))
                {
                    String[] tmp = s.Split();
                    var input = new float[tmp.Length];
                    for (int i = 0; i < tmp.Length; i++)
                        input[i] = float.Parse(tmp[i]);
                    trainingDataSet.Add(input);
                }

                var expectedOutputs = new List<float[]>();
                foreach (String s in File.ReadLines(Properties.Settings.Default.TrainingDataResponsesPath))
                {
                    String[] tmp = s.Split();
                    var expectedOutput = new float[tmp.Length];
                    for (int i = 0; i < tmp.Length; i++)
                        expectedOutput[i] = float.Parse(tmp[i]);
                    expectedOutputs.Add(expectedOutput);
                }

                var bpNetwork = n as BpNetwork;

                int iterations = 0;
                foreach (var ss in File.ReadLines(Properties.Settings.Default.TrainingPropertiesPath))
                {
                    String[] tmp2 = ss.Split();
                    var gamma = float.Parse(tmp2[1]);
                    var momentum = float.Parse(tmp2[2]);
                    var epocs = int.Parse(tmp2[0]);
                    for (var ii = 0; ii < epocs - iterations; ii++)
                    {
                        for (var errInd = 0; errInd < bpNetwork.Err.Length; errInd++)
                            bpNetwork.Err[errInd] = 0;
                        for (var j = 0; j < trainingDataSet.Count; j++)
                        {
                            bpNetwork.InputSignals = trainingDataSet[j];
                            bpNetwork.Learn(expectedOutputs[j], gamma, momentum);
                        }
                    }
                    iterations = epocs;
                    var err = 0.0;
                    for (int i = 0; i < bpNetwork.Layers.LastOrDefault().Size; i++)
                        err += bpNetwork.Err[i];
                    err = Math.Sqrt(err/(double) (bpNetwork.Layers.LastOrDefault().Size*trainingDataSet.Count));
                    Console.WriteLine(string.Format("Blad = {0}", err));
                }

                foreach (var baseLayer in bpNetwork.Layers)
                {
                    baseLayer.PrintWeights();
                }
            }
            else
            {

                if ((n.Layers[0] as KohonenLayer) != null)
                {
                    var trainingDataSet = new List<float[]>();
                    foreach (String s in File.ReadLines(Properties.Settings.Default.TrainingDataPath))
                    {
                        String[] tmp = s.Split();
                        var input = new float[tmp.Length];
                        for (int i = 0; i < tmp.Length; i++)
                            input[i] = float.Parse(tmp[i]);
                        trainingDataSet.Add(input);
                    }

                    var kl = (KohonenLayer) n.Layers[0];
                    float[][] trainingSet = trainingDataSet.ToArray();
                    int iterations = 0;
                    foreach (String s in File.ReadLines(Properties.Settings.Default.TrainingPropertiesPath))
                    {
                        String[] tmp = s.Split();
                        KohonenLayer.NeighbourhoodType nbhrType;
                        KohonenLayer.NeighbourhoodType.TryParse(tmp[2], true, out nbhrType);
                        kl.Learn(int.Parse(tmp[0]) - iterations, float.Parse(tmp[1]), nbhrType, int.Parse(tmp[3]),
                                 float.Parse(tmp[4]),
                                 trainingSet);
                        iterations = int.Parse(tmp[0]);
                    }
                    Console.WriteLine("Kohonen weights:");
                    kl.PrintWeights();
                    Console.WriteLine();

                    if ((n.Layers[1] as GrossbergLayer) != null)
                    {
                        var gl = (GrossbergLayer) n.Layers[1];

                        var expectedOutputs = new List<float[]>();
                        foreach (String s in File.ReadLines(Properties.Settings.Default.TrainingDataResponsesPath))
                        {
                            String[] tmp = s.Split();
                            var expectedOutput = new float[tmp.Length];
                            for (int i = 0; i < tmp.Length; i++)
                                expectedOutput[i] = float.Parse(tmp[i]);
                            expectedOutputs.Add(expectedOutput);
                        }

                        iterations = 0;
                        foreach (
                            var ss in File.ReadLines(Properties.Settings.Default.TrainingPropertiesForGrossbergLayerPath))
                        {
                            String[] tmp2 = ss.Split();
                            var gamma = float.Parse(tmp2[1]);
                            var momentum = float.Parse(tmp2[2]);
                            for (var ii = 0; ii < int.Parse(tmp2[0]) - iterations; ii++)
                                for (var j = 0; j < trainingDataSet.Count; j++)
                                {
                                    kl.ProcessNeurons(trainingDataSet[j]);
                                    var kohonenOutput = kl.GetOutputSignals();
                                    gl.Learn(kohonenOutput, expectedOutputs[j], gamma, momentum);
                                }
                            iterations = int.Parse(tmp2[0]);
                        }

                        Console.WriteLine("GrossbergLayer weights:");
                        gl.PrintWeights();
                        Console.WriteLine();
                    }
                }   
            }

            foreach (var input in inputDataSet)
            {
                RunCase(n, input);
            }
            Console.ReadKey();
        }

        private static void RunCase(Network n, float[] input)
        {
            foreach (float y in input)
                Console.Out.Write(y + " ");
            Console.Out.Write("=> ");
            n.InputSignals = input;
            n.Process();
            foreach (float y in n.GetOutputSignals())
            {Console.Out.Write(y + " ");}
            Console.Out.WriteLine("\n---------------");
        }
    }
}
